﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DigitsExtractor;
using NeuralNetwork;

namespace DigitsRecognizer.UI
{
    public class TrainingForm : Form
    {
        private string Login = "piotrek";
        private Label DescriptionLabel, TrainingParamLabel, EpochsLabel, EdgeValueLabel, ProgressLabel;
        private TextBox TrainingParamTB, EpochsTB, EdgeValueTB;
        private Button TrainButton, CancelButton;
        private ProgressBar ProgressBar;
        private ToolTip TrainingTT, EpochsTT, EdgeValueTT;

        private NeuralNetwork<double> NeuralNetwork;
        private DigitExtractor DigitExtractor;

        public TrainingForm() 
        {
            NeuralNetwork = new NeuralNetwork<double>();

            this.Height = 250;
            this.Width = 300;
            this.CenterToScreen();
            this.MinimizeBox = false;
            this.MaximizeBox = false;
            this.Text = "Trening";

            DescriptionLabel = new Label();
            DescriptionLabel.AutoSize = true;
            DescriptionLabel.Text = "Trenowanie";
            DescriptionLabel.Location = new Point(100, 7);
            DescriptionLabel.Font = new Font(new FontFamily(System.Drawing.Text.GenericFontFamilies.SansSerif), 10, FontStyle.Italic);

            TrainingParamLabel = new Label();
            TrainingParamLabel.AutoSize = true;
            TrainingParamLabel.Text = "Parametr uczenia:";
            TrainingParamLabel.Location = new Point(35, 45);

            TrainingParamTB = new TextBox();
            TrainingParamTB.AutoSize = true;
            TrainingParamTB.Text = "0,0001";
            TrainingParamTB.TextAlign = HorizontalAlignment.Right;
            TrainingParamTB.Location = new Point(150, 42);
            TrainingParamTB.Width = 80;

            TrainingTT = new ToolTip();
            TrainingTT.UseAnimation = true;
            TrainingTT.IsBalloon = true;
            TrainingTT.SetToolTip(TrainingParamTB, "Parametr określający szybkość uczenia się sieci. \nIm mniejsza wartość tym sieć będzie dokładniej uczona, \nco wymagać będzie dodatkowego czasu");

            EpochsLabel = new Label();
            EpochsLabel.AutoSize = true;
            EpochsLabel.Text = "Liczba epok:";
            EpochsLabel.Location = new Point(59, 70);

            EpochsTB = new TextBox();
            EpochsTB.AutoSize = true;
            EpochsTB.Text = "";
            EpochsTB.TextAlign = HorizontalAlignment.Right;
            EpochsTB.Location = new Point(150, 67);
            EpochsTB.Width = 80;

            EpochsTT = new ToolTip();
            EpochsTT.UseAnimation = true;
            EpochsTT.IsBalloon = true;
            EpochsTT.SetToolTip(EpochsTB, "Parametr będący warunkiem stopu uczenia się sieci. \nOkreśla ilość iteracji w procesie uczenia, dla zbioru treningowego \njednej klasy");

            EdgeValueLabel = new Label();
            EdgeValueLabel.AutoSize = true;
            EdgeValueLabel.Text = "Błąd progowy:";
            EdgeValueLabel.Location = new Point(51, 95);

            EdgeValueTB = new TextBox();
            EdgeValueTB.AutoSize = true;
            EdgeValueTB.Text = "0,000001";
            EdgeValueTB.TextAlign = HorizontalAlignment.Right;
            EdgeValueTB.Location = new Point(150, 92);
            EdgeValueTB.Width = 80;

            EdgeValueTT = new ToolTip();
            EdgeValueTT.UseAnimation = true;
            EdgeValueTT.IsBalloon = true;
            EdgeValueTT.SetToolTip(EdgeValueTB, "Parametr określający maksymalny próg błędu przy \nwyznaczaniu wzórca dla danego zbioru treningowego");

            ProgressLabel = new Label();
            ProgressLabel.AutoSize = true;
            ProgressLabel.Text = "Trenowanie w toku...";
            ProgressLabel.Visible = false;
            ProgressLabel.Location = new Point(29, 120);

            ProgressBar = new ProgressBar();
            ProgressBar.UseWaitCursor = true;
            ProgressBar.Style = ProgressBarStyle.Marquee;
            ProgressBar.Location = new Point(150, 117);
            ProgressBar.Visible = false;
            ProgressBar.Size = new Size(80, 20);

            TrainButton = new Button();
            TrainButton.Text = "Trenuj";
            TrainButton.Location = new Point(50, 175);

            CancelButton = new Button();
            CancelButton.Text = "Powrót";
            CancelButton.Location = new Point(160, 175);

            this.Controls.Add(DescriptionLabel);
            this.Controls.Add(TrainingParamLabel);
            this.Controls.Add(TrainingParamTB);
            this.Controls.Add(EpochsLabel);
            this.Controls.Add(EpochsTB);
            this.Controls.Add(EdgeValueLabel);
            this.Controls.Add(EdgeValueTB);
            this.Controls.Add(ProgressLabel);
            this.Controls.Add(ProgressBar);
            this.Controls.Add(TrainButton);
            this.Controls.Add(CancelButton);

            /* obsługa wciśnięcia przycisku Cancel */
            EventHandler cancelButtonEH = new EventHandler(OnClickCancel);
            CancelButton.Click += cancelButtonEH;

            /* obsługa wciśnięcia przycisku Train */
            EventHandler trainButtonEH = new EventHandler(OnClickTrain);
            TrainButton.Click += trainButtonEH;
        }

        public TrainingForm(string login)
            : this()
        {
            Login = login;
        }

        private void OnClickCancel(object sender, EventArgs args)
        {
            this.Close();
        }

        private void OnClickTrain(object sender, EventArgs args)
        {
            DisableElements();
            double n = Convert.ToDouble(TrainingParamTB.Text.Trim());
            Nullable<int> epochs = EpochsTB.Text.Trim() != string.Empty ? (Nullable<int>)Convert.ToInt32(EpochsTB.Text.Trim()) : null;
            double edgeValue = Convert.ToDouble(EdgeValueTB.Text.Trim());
            NeuralNetwork.Train(n, epochs, edgeValue, Login);
            MessageBox.Show("Sieć została wytrenowana.", "Trenowanie sieci", MessageBoxButtons.OK, MessageBoxIcon.Information);
            EnableElements();
        }

        private void DisableElements()
        {
            ProgressBar.Visible = true;
            ProgressLabel.Visible = true;
            TrainButton.Enabled = false;
            EpochsTB.Enabled = false;
            TrainingParamTB.Enabled = false;
            TrainingParamLabel.Enabled = false;
            EpochsLabel.Enabled = false;
            ProgressLabel.Refresh();
            ProgressBar.Refresh();
        }

        private void EnableElements()
        {
            ProgressBar.Visible = false;
            ProgressLabel.Visible = false;
            TrainButton.Enabled = true;
            EpochsTB.Enabled = true;
            TrainingParamTB.Enabled = true;
            TrainingParamLabel.Enabled = true;
            EpochsLabel.Enabled = true;
        }

    }
}
